package me.cabbit.digitone.tones;

import java.awt.Graphics2D;
import java.util.ArrayList;

import javax.swing.JPanel;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Element;


/**
 * Abstract class representing a screentone. To implement your own screentone
 * inherit from this class and implement the abstract methods.
 * 
 * @author Arkaid
 *
 */
public abstract class Screentone {

	//------------------------------------------------------------------//
	//------------------------ abstract methods ------------------------//
	//------------------------------------------------------------------//

	/**
	 * Returns a {@link JPanel} with the options to handle the screentone
	 * parameters
	 * 
	 * @return JPanel to add to the interface
	 */
	public abstract JPanel getPanel();
	
	/**
	 * Gets the name of this screentone. Should use {@link String} to 
	 * internationalize it properly 
	 * 
	 * @return Name of the screentone
	 */
	public abstract String getName();
	
	/**
	 *  Returns a unique identifier. Each subclass should 
	 * return a unique string. You can build one 
	 * <a href=http://www.guidgenerator.com/online-guid-generator.aspx>here</a>
	 *   
	 * @return a unique string
	 */
	public abstract String getUID();
	
	/** 
	 * Save the screentone settings into an xml Element node. You could either
	 * add subnodes or append attributes, but must not change what is already 
	 * inside the node
	 * 
	 * @param node node to save information to (in / out parameter)
	 */
	public abstract void savePreset(Element node);
	
	/**
	 * Node with information to load settings. Complements savePreset()
	 * 
	 * @param node the node to load information from
	 */
	public abstract void loadPreset(Element node);
	
	
	/**
	 * Using the current parameters, render the screentone into the
	 * given {@link Graphics2D} object
	 * @param target {@link Graphics2D} instance to render to
	 */
	public abstract void render(Graphics2D target);
	
	//------------------------------------------------------------------//
	//--------------------------- properties ---------------------------//
	//------------------------------------------------------------------//

	/** Listeners */
	ArrayList<ScreentoneListener> listeners;
	
	/** Screentone width */
	private int width;
	
	/** Screentone height */
	private int height;

	//------------------------------------------------------------------//
	//----------------------------- methods ----------------------------//
	//------------------------------------------------------------------//

	/** 
	 * Constructor. Set default size to 512 512 
	 * 
	 * @throws ParserConfigurationException when it fails to create the xml document */
	public Screentone()  
	{
		this.listeners = new ArrayList<ScreentoneListener>();
        setSize(512, 512);        
	}

	/** 
	 * Sets the size of the screntone
	 * 
	 * @param w new width
	 * @param h new height
	 */
	public void setSize(int w, int h) 
	{
		this.width = w;
		this.height = h;
		
		raisePropertyChangedEvent();
	}
	
	/** 
	 * Returns the width of the screentone
	 * 	 
	 * @return width of the screentone
	 */
	public int getWidth() 
	{
		return this.width;
	}
	
	/** 
	 * Returns the height of the screentone
	 * 	 
	 * @return height of the screentone
	 */
	public int getHeight() 
	{
		return this.height;
	}

	/** Add a listener for screentone events */
	public void addScreentoneListener(ScreentoneListener l)
	{
		this.listeners.add(l);
	}
	
	/** Remove a listener for screentone events */
	public void removeScreentoneListener(ScreentoneListener l)
	{
		this.listeners.remove(l);
	}
	
	/**
	 * Raises a progress change event. Notifies all listeners
	 * @param progress a value representing progress from 0 to 100
	 */
	protected void raiseBuildProgressChangedEvent(int progress)
	{
		int len = this.listeners.size();
		for (int i = 0; i < len; i++)
			this.listeners.get(i).buildProgressChanged(progress);
	}

	/**
	 * Raises a property change event. Notifies all listeners. You want
	 * to use this when an option value has changed
	 */
	protected void raisePropertyChangedEvent()
	{
		int len = this.listeners.size();
		for (int i = 0; i < len; i++)
			this.listeners.get(i).propertyChanged();
	}
	
	@Override
	public String toString() {
		return this.getName();
	}
}
